package com.ljx.itbbs.server.mall.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.ljx.itbbs.common.constant.CacheConstants;
import com.ljx.itbbs.common.exception.BusinessException;
import com.ljx.itbbs.common.utils.AssertUtil;
import com.ljx.itbbs.common.utils.RedisUtil;
import com.ljx.itbbs.server.mall.consumer.CouponConsumer;
import com.ljx.itbbs.server.mall.domain.vo.req.CouponSaveReq;
import com.ljx.itbbs.server.mall.domain.vo.req.CouponUpdateReq;
import com.ljx.itbbs.server.mall.domain.vo.resp.CouponAdminResp;
import com.ljx.itbbs.server.mall.event.CouponSaveEvent;
import com.ljx.itbbs.server.mall.service.adapter.CouponAdapter;
import com.ljx.itbbs.server.mq.domain.mall.CouponMsgDto;
import com.ljx.itbbs.server.mq.service.RabbitMQProducer;
import com.ljx.itbbs.server.mall.dao.CouponDao;
import com.ljx.itbbs.server.mall.domain.entity.CouponEntity;
import com.ljx.itbbs.server.mall.domain.entity.CouponRecordEntity;
import com.ljx.itbbs.server.mall.domain.enums.CouponSeckillEnum;
import com.ljx.itbbs.server.mall.domain.vo.resp.CouponResp;
import com.ljx.itbbs.server.mall.service.CouponRecordService;
import com.ljx.itbbs.server.mall.service.CouponService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Date;
import java.util.List;

import static com.ljx.itbbs.server.mall.consumer.CouponConsumer.COUPON_EXCHANGE;
import static com.ljx.itbbs.server.mall.consumer.CouponConsumer.COUPON_KEY;

@Service
public class CouponServiceImpl implements CouponService {

    @Autowired
    private CouponDao couponDao;

    @Autowired
    private CouponRecordService couponRecordService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    // Lua脚本
    private static final DefaultRedisScript<Long> SECKILL_SCRIPT;

    static {
        SECKILL_SCRIPT = new DefaultRedisScript<>();
        SECKILL_SCRIPT.setLocation(new ClassPathResource("coupon.lua"));
        SECKILL_SCRIPT.setResultType(Long.class);
    }


    @Override
    public List<CouponResp> getUserCouponList(Long userId) {
        return BeanUtil.copyToList(couponDao.getUserCouponListByUId(userId), CouponResp.class);
    }

    @Override
    public CouponEntity getById(Long couponId) {
        return couponDao.getById(couponId);
    }

    @Override
    public List<CouponResp> getCouponList() {
        return BeanUtil.copyToList(couponDao.list(), CouponResp.class);
    }

    @Override
    public void seckill(Long userId, Long couponId) {
        check(couponId);
        Long result = stringRedisTemplate.execute(
                SECKILL_SCRIPT,
                Collections.emptyList(),
                couponId.toString(),
                userId.toString()
        );
        // 返回异常信息
        CouponSeckillEnum couponSeckillEnum = CouponSeckillEnum.of(result);
//        AssertUtil.equal(couponSeckillEnum, CouponSeckillEnum.OK, couponSeckillEnum.getDesc());
        if (!couponSeckillEnum.equals(CouponSeckillEnum.OK)) {
            throw new BusinessException(couponSeckillEnum.getDesc());
        }
        // 发送消息队列
        rabbitTemplate.convertAndSend(COUPON_EXCHANGE, COUPON_KEY, new CouponMsgDto(userId, couponId));

    }

    private void check(Long couponId) {
        CouponEntity couponEntity = couponDao.getById(couponId);
        // 查询是否在有效期
        Date now = new Date();
        AssertUtil.isFalse(now.before(couponEntity.getBeginTime()) || now.after(couponEntity.getEndTime()), "不在有效时间范围内");
    }

    @Override
    public void reduceStock(Long couponId) {
        couponDao.reduceStock(couponId);
    }

    @Override
    public CouponEntity getUserCoupon(Long userId, Long couponId) {
        return couponDao.getUserCoupon(userId, couponId);
    }


    @Override
    @Transactional
    public void saveCoupon(CouponSaveReq req) {
        CouponEntity couponEntity = CouponAdapter.buildCouponSave(req);
        applicationEventPublisher.publishEvent(new CouponSaveEvent(this, couponEntity));
    }

    @Override
    public void updateCoupon(CouponUpdateReq req) {

    }

    @Override
    public List<CouponAdminResp> getAdminCouponList() {
        return BeanUtil.copyToList(couponDao.list(), CouponAdminResp.class);
    }
}
